using System;
using System.Collections.Generic;
using System.Text;

namespace RapidHDL
{
    public class ExternalFIFOInterface : Component 
    {
        public NodeVector OutputFIFOData; //16
        public NodeVector OutputFIFOWrite; //1
        public NodeVector OutputFIFORead; //1
        public NodeVector InputFIFOData; //18
        public NodeVector InputStatusReg; //2

        public NodeVector Test;

        public NodeVector OutputExternalFIFO;
        ClockComponent oClock;

        PipelineBus  oBusInput;
        PipelineBus oBusOutput;

        NodeVector nvReset;

        public bool Enabled=false;

        public ExternalFIFOInterface(Component poParentComponent, string psName, ClockComponent poClock, NodeVector pnvReset, int piWidthFromExternal, int piWidthFromInternal)
            : base(poParentComponent, psName)
        {
            OutputFIFOData = this.CreateNodeVector("o_fifo_data", piWidthFromInternal);
            OutputFIFOWrite = this.CreateNodeVector("o_fifo_write", 1);
            OutputFIFORead = this.CreateNodeVector("o_fifo_read", 1);
            InputFIFOData = this.CreateNodeVector("i_fifo_data", piWidthFromExternal);
            InputStatusReg = this.CreateNodeVector("i_status_reg", 2);
            //Test = this.CreateNodeVector("test", 1);

            nvReset = pnvReset;
            oClock = poClock;

            oBusInput = new PipelineBus(this, "input_pipe", piWidthFromExternal);
            oBusOutput = new PipelineBus(this, "output_pipe", piWidthFromInternal);
            
        }

        public PipelineBus BusFromInternal
        {
            get { return oBusOutput; } 
        }

        public PipelineBus BusFromExternal
        {
            get { return oBusInput; }
        }

        public override void GenerateStructure()
        {
            NodeVector nvOutputFull;
            NodeVector nvInputEmpty;

            nvOutputFull = InputStatusReg.Subset(this,1,1);
            nvInputEmpty = InputStatusReg.Subset(this,0,0);

            oBusOutput.Data.Join(OutputFIFOData);
            oBusOutput.Stall.Join(nvOutputFull);
            OutputFIFOWrite.Join(oBusOutput.DataReady);

            oBusInput.Data.Join(InputFIFOData);
            //JNA changed here
            OutputFIFORead.Join((!oBusInput.Stall) & (!nvInputEmpty));
            oBusInput.DataReady.Join(!nvInputEmpty);

            if (!Enabled)
            {
                PipelineStage oPipeSync = new PipelineStage(this, "loopback", oClock, nvReset, BusFromExternal.Data.Width);

                oPipeSync.InputBus.Join(BusFromExternal);

                int iWidth = oBusInput.Data.Width;
                if (iWidth > oBusOutput.Data.Width)
                    iWidth = oBusOutput.Data.Width;
                PipelineReMap oPipeMap = new PipelineReMap(oPipeSync.OutputBus, BusFromInternal);
                oPipeMap.DefineMap(0, iWidth, 0, true);
                oPipeMap.CompleteMap();
                if (iWidth < oBusOutput.Data.Width)
                    oBusOutput.Data.Subset(this, iWidth, oBusOutput.Data.Width - 1).Join(0);
            }
        }        

    }
}
